import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * @description: 实现Callable
 * @author: zys
 * @create: 2020-10-11 13:19
 **/
public class MyCallable implements Callable<String> {

    /**
     * 1创建Callable接口的实现类，并实现call()方法，该call()方法将作为线程执行体，并且有返回值。
     * 2创建Callable实现类的实例，使用FutureTask类来包装Callable对象，
     * 该FutureTask对象封装了该Callable对象的call()方法的返回值。
     * 3使用FutureTask对象作为Thread对象的target创建并启动新线程。
     * 4调用FutureTask对象的get()方法来获得子线程执行结束后的返回值
     */
    @Override
    public String call() throws Exception {
        return doSomeThing();
    }

    private String doSomeThing() {
        System.out.println("hello MyCallable.");
        return "success";
    }

    public static void main(String[] args) {
        //创建FutureTask对象，并将Callable对象传入FutureTask的构造方法中
        Callable<String> callable = new MyCallable();
        //Callable不能直接获取返回值，需要用FutureTask<V>在外部封装一下再获取返回值
        //实例化Thread对象，并在构造方法中传入FutureTask对象
        FutureTask<String> futureTask = new FutureTask<String>(callable);
        Thread thread = new Thread(futureTask);
        //开启一个线程方法
        thread.start();

        try {
            //获取线程返回值
            System.out.println(futureTask.get());
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }


    /**
     *  总结
     *  采用继承Thread类方式：
     * 　　　（1）优点：编写简单，如果需要访问当前线程，无需使用Thread.currentThread()方法，直接使用this，即可获得当前线程。
     * 　　　（2）缺点：因为线程类已经继承了Thread类，所以不能再继承其他的父类。
     *  采用实现Runnable接口方式：
     * 　　　（1）优点：线程类只是实现了Runable接口，还可以继承其他的类。在这种方式下，可以多个线程共享同一个目标对象，
     * 所以非常适合多个相同线程来处理同一份资源的情况，从而可以将CPU代码和数据分开，形成清晰的模型，较好地体现了面向对象的思想。
     * 　　　（2）缺点：编程稍微复杂，如果需要访问当前线程，必须使用Thread.currentThread()方法。
     *
     * Runnable和Callable的区别：
     * 　　　(1)Callable规定的方法是call(),Runnable规定的方法是run().
     * 　　　(2)Callable的任务执行后可返回值，而Runnable的任务是不能返回值得
     * 　　　(3)call方法可以抛出异常，run方法不可以，因为run方法本身没有抛出异常，
     * 所以自定义的线程类在重写run的时候也无法抛出异常
     * 　　　(4)运行Callable任务可以拿到一个Future对象，表示异步计算的结果。它提供了检查计算是否完成的方法，
     * 以等待计算的完成，并检索计算的结果。通过Future对象可以了解任务执行情况，可取消任务的执行，还可获取执行结果。
     */
}
